﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Ahresty
{
    /// <summary>
    /// ADSTEFAN用の.in3dファイルを表すクラス
    /// </summary>
    internal class IN3DData
    {
        #region Fields

        private const int ROW_MAX_LENGTH = 800;

        #endregion


        #region Properties

        internal short MaxX { get; set; }

        internal short MaxY { get; set; }

        internal short MaxZ { get; set; }

        internal short StartLineIndex { get; set; }

        internal byte MaterialID { get; set; }

        internal byte[, ,] Data { get; set; }

        internal string SourceFilePath { get; set; }

        internal int XRowCount { get; set; }

        #endregion


        #region Constructors

        internal IN3DData(string in3dFilePath, byte materialID)
        {
            this.SourceFilePath = in3dFilePath;

            this.MaterialID = materialID;
            string[] lines = File.ReadAllLines(in3dFilePath);

            this.MaxX = this.MaxY = this.MaxZ = this.StartLineIndex = 0;
            this.XRowCount = 1;

            for (int n = 0; n < lines.Length; n++)
                if (lines[n].Equals("C", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.StartLineIndex = (short)n;

                    while (lines[n + this.XRowCount].Length == IN3DData.ROW_MAX_LENGTH)
                        this.XRowCount++;

                    this.MaxX = (short)((this.XRowCount - 1) * IN3DData.ROW_MAX_LENGTH + lines[n + this.XRowCount].Length);

                    while (!lines[n + 1].Equals("C", StringComparison.InvariantCultureIgnoreCase) &&
                        !lines[n + 1].Equals("$END_IN3D", StringComparison.InvariantCultureIgnoreCase))
                    {
                        this.MaxY++;
                        n += this.XRowCount;
                    }
                    break;
                }
            foreach (string line in lines)
                if (line.Equals("C", StringComparison.InvariantCultureIgnoreCase))
                    this.MaxZ++;

            this.Data = new byte[this.MaxX, this.MaxY, this.MaxZ];
            for (int n = this.StartLineIndex; n < lines.Length; n++)
            {
                string line = lines[n];

                if (!line.Equals("C", StringComparison.InvariantCultureIgnoreCase) &&
                    !line.Equals("$END_IN3D", StringComparison.InvariantCultureIgnoreCase))
                {
                    for (int m = 1; m <= this.XRowCount - 1; m++)
                        line += lines[n + m];
                    char[] chars = line.ToCharArray();

                    int y = ((n - this.StartLineIndex) % (this.MaxY * this.XRowCount + 1) - 1) / this.XRowCount;
                    int z = (n - this.StartLineIndex) / (this.MaxY * this.XRowCount + 1);
                    for (int x = 0; x < chars.Length; x++)
                        this.Data[x, y, z] = BitConverter.GetBytes(chars[x])[0];

                    n += this.XRowCount - 1;
                }
            }
        }

        #endregion


        #region Methods

        internal void Output(string destFilePath)
        {
            List<string> fileContents = new List<string>();

            foreach (string line in File.ReadAllLines(this.SourceFilePath))
                if (!line.Equals("$MESH_MATERIAL"))
                    fileContents.Add(line);
                else
                    break;

            fileContents.Add("$MESH_MATERIAL");
            for (short z = 0; z < this.MaxZ; z++)
            {
                fileContents.Add("C");

                for (short y = 0; y < this.MaxY; y++)
                {
                    string line;

                    for (int n = 0; n < this.XRowCount; n++)
                    {
                        line = String.Empty;
                        for (int x = 0; x < IN3DData.ROW_MAX_LENGTH; x++)
                        {
                            int xIndex = x + n * IN3DData.ROW_MAX_LENGTH;
                            if (xIndex >= this.MaxX)
                                break;

                            line += (char)this.Data[xIndex, y, z];
                        }
                        fileContents.Add(line);
                    }
                }
            }

            fileContents.Add("$END_IN3D");

            File.WriteAllLines(destFilePath, fileContents.ToArray());
        }

        #endregion
    }
}
